#define _CRT_SECURE_NO_WARNINGS 1

#include "Book.h"

DLNode* DListInit()
{
    DLNode* pHead = (DLNode*)malloc(sizeof(DLNode));
    if (pHead == NULL)
    {
        printf("malloc failed!\n");
        exit(-1);
    }
    pHead->next = pHead;
    pHead->prev = pHead;

    LoadBook(pHead); // 从文件中读取书库函数

    return pHead;
    //这里我们使用 malloc 函数开辟一块空间作为 "哨兵位" pHead ，
    //最后将其进行一个初始化。最后再将 pHead 作为结果返回回去，外面就可以接收到了。
    //这就是返回值的方法，当然这里也可以采用二级指针的方法来完成。
}

void LoadBook(DLNode* pHead)
{
    FILE* pf = fopen("book.dat", "r");
    if (pf == NULL)
    {
        perror("LoadBook");
        printf("此时书库内无书。\n");
        return;
    }
    else
    {
        printf("此时书库内有书，可输入2查看。\n");
    }

    struct Book s = { 0 }; // 存放处
    while(fread(&s, sizeof(Book), 1, pf))
    {
        //printf("%s %s %s %d %d\n", s.auther, s.book_name, s.book_number, s.now_num, s.stock_num);// 将读到的数据打印
        //DListPushBack();自己一步实现尾插：

        DLNode* newNode = (DLNode*)malloc(sizeof(DLNode));
        if (newNode == NULL)
        {
            printf("malloc failed!\n");
            exit(-1);
        }
        strcpy(newNode->data.book_number, s.book_number);
        strcpy(newNode->data.book_name, s.book_name);
        strcpy(newNode->data.auther, s.auther);
        newNode->data.now_num = s.now_num;
        newNode->data.stock_num = s.stock_num;

        DLNode* tail = pHead->prev;

        tail->next = newNode;//原尾指向新尾
        newNode->prev = tail;//新尾指回原尾
        pHead->prev = newNode;//哨兵指到新尾
        newNode->next = pHead;//新尾指回哨兵
    }

    fclose(pf);//关闭文件
    pf = NULL;
}

DLNode* CreateNewNode(char* booknumber_tmp)
{
    DLNode* newNode = (DLNode*)malloc(sizeof(DLNode));
    if (newNode == NULL)
    {
        printf("malloc failed!\n");
        exit(-1);
    }

    printf("此书书库不存在，请输入下面信息\n");
    strcpy(newNode->data.book_number, booknumber_tmp); // 书号
    printf("书名: ");
    scanf("%s", newNode->data.book_name);
    printf("书作者: ");
    scanf("%s", newNode->data.auther);
    int num = 0;
    printf("要入库这本书的数量: ");
    scanf("%d", &num);
    newNode->data.now_num = num;
    newNode->data.stock_num = num;

    newNode->next = NULL;
    newNode->prev = NULL;
    return newNode;
}

void DListPushBack(DLNode* pHead,char* arr_number)
{
    assert(pHead != NULL);
    //DLNode* tail = pHead->prev;
    //DLNode* newNode = CreateNewNode(x);

    //tail->next = newNode;//原尾指向新尾
    //newNode->prev = tail;//新尾指回原尾
    //pHead->prev = newNode;//哨兵指到新尾
    //newNode->next = pHead;//新尾指回哨兵

    DListInsert(pHead, arr_number);//在pHead的前一个插入就是尾插
}

void PrintOneBook(DLNode* cur)
{
    printf("书号：%s\n", cur->data.book_number);
    printf("书名：《%s》\n", cur->data.book_name);
    printf("著作者：%s\n", cur->data.auther);
    printf("现存量：%d\n", cur->data.now_num);
    printf("库存量：%d\n\n", cur->data.stock_num);
}

void DListPrint(DLNode* pHead)
{
    //用结构体指针 pHead 接收， 这里的 pHead 表示哨兵位。
    assert(pHead != NULL);
    DLNode* cur = pHead->next;
    //遍历链表就需要从 pHead->next 开始（即第一个有效数据节点）
    //当 cur 等于 pHead 就相当于全部走了一遍了，这时就结束。
    if (cur == pHead)
    {
        printf("\n书库内无图书。\n");
    }
    else
    {
        printf("\n<展示书库图书>\n");
        while (cur != pHead)
        {
            PrintOneBook(cur);

            cur = cur->next;
        }
    }
}

DLNode* DListFind(DLNode* pHead, char* arr_number)
{
    assert(pHead != NULL);
    DLNode* cur = pHead->next;
    //遍历链表就需要从 pHead->next 开始（即第一个有效数据节点）（和打印一样）
    //当 cur 等于 pHead 就相当于全部走了一遍了，这时就结束。
    while (cur != pHead)
    {
        if (strcmp(cur->data.book_number, arr_number) == 0)//根据书号查找，找到了就返回这个结点
        {
            return cur;
        }
        cur = cur->next;
    }
    return NULL;
}

void DListInsert(DLNode* pos, char* arr_number)//在pos之前插入
{
    assert(pos != NULL);
    DLNode* newNode = CreateNewNode(arr_number);
    DLNode* posPrev = pos->prev;//记录pos前节点
    posPrev->next = newNode;//pos前节点指向新节点
    newNode->prev = posPrev;//新节点指回pos前节点

    newNode->next = pos;//新节点指向pos 
    pos->prev = newNode;//pos指回新节点
}

void AddBook(DLNode* pHead)
{
    printf("\n<采编入库>\n");
    printf("请输入采编入库的书的书号：");

    char booknumber_tmp[20]; // 书号
    scanf("%s", booknumber_tmp);
    DLNode* tmp = DListFind(pHead, booknumber_tmp);
    if (tmp != NULL)
    {
        printf("此书号图书已存在\n");
        int num = 0;
        printf("要入库这本书的数量: ");
        scanf("%d", &num);
        tmp->data.now_num += num;
        tmp->data.stock_num += num;
        printf("库存和现存量已改变: \n\n");
    }
    else
    {
        DListPushBack(pHead, booknumber_tmp);
        printf("添加新书成功！ \n\n");
    }
}

void DListDestory(DLNode* pHead)//保持接口函数的一致性就不传二级了，让使用者自己置空
{
    assert(pHead != NULL);
    DLNode* cur = pHead->next;
    while (cur != pHead)
    {
        DLNode* curNext = cur->next;
        free(cur);
        cur = curNext;
    }
    free(pHead);
    pHead = NULL;//不能使外面置空，让使用者自己置空
}

void DListEarse(DLNode* pos)
{
    assert(pos != NULL);
    assert(pos->next != pos);//防止删掉哨兵位头节点
    DLNode* posPrev = pos->prev;
    DLNode* posNext = pos->next;

    posPrev->next = posNext;//pos前节点指向pos后节点
    posNext->prev = posPrev;//pos后节点指回pos前节点
    free(pos);
    pos = NULL;//不置空也行
}

void DListPopBack(DLNode* pHead ,char* arr_number)
{
    assert(pHead != NULL);
    assert(pHead->next != pHead);//防止删掉哨兵位头节点
    //DLNode* tali = pHead->prev;//记录原尾等下释放
    //pHead->prev = pHead->prev->prev;//头链接到新尾
    //pHead->prev->next = pHead;//新尾链接到头
    //free(tali);

    DListEarse(pHead->prev);
}

void DListPushFront(DLNode* pHead, char* arr_number)
{
    assert(pHead != NULL);
    //DLNode* newNode = CreateNewNode(x);
    //pHead->next->prev = newNode;//原一指回新一
    //newNode->next = pHead->next;//新一指向原一
    //pHead->next = newNode;//哨兵指向新一
    //newNode->prev = pHead;//新一指回哨兵
    ////空链表也能头插

    DListInsert(pHead->next, arr_number);//在pHead的前一个就是插入就是头删
}

void DListPopFront(DLNode* pHead)
{
    assert(pHead != NULL);
    assert(pHead->next != pHead);//防止删掉哨兵位头节点
    //DLNode* head = pHead->next;//记录原一等下释放
    //pHead->next = head->next;//哨兵头指向原二
    //head->prev = pHead;//原二指回哨兵头
    //free(head);
    //head = NULL;//不置空也行

    DListEarse(pHead->next);
}

void SaveBook(DLNode* pHead)
{
    assert(pHead != NULL);
    FILE* pf = fopen("book.dat", "w");
    if (pf == NULL)
    {
        perror("SaveBook");
        return;
    }
    //写文件
    DLNode* cur = pHead->next;
    //遍历链表就需要从 pHead->next 开始（即第一个有效数据节点）
    //当 cur 等于 pHead 就相当于全部走了一遍了，这时就结束。
    while (cur != pHead)
    {
        fwrite(&(cur->data), sizeof(Book), 1, pf);

        cur = cur->next;
    }
    fclose(pf);
    pf = NULL;
}